using System.ComponentModel;
using System.Configuration.Install;

using System.IO;

namespace TaskService.CustomInstallActions
{
    /// <summary>
    /// Creates the custom folder properties during the installation.
    /// </summary>
   [RunInstaller(true)]
   public partial class CustomFolderProperties : Installer
   {
       /// <summary>
       /// Initializes a new instance of the <see cref="CustomFolderProperties"/> class.
       /// </summary>
      public CustomFolderProperties ()
      {
         InitializeComponent();
      }

      #region Private Variables
      private const string LOG_FOLDER = "Logs";
      private const string PLUGIN_FOLDER = "Plugins";
      private const string PLUGIN_ICON = "folder_plugin.ico";
      private const string LOG_FOLDER_ICON = "folder_logs.ico";
      #endregion Private Variables

      #region Installer Implementation

      /// <summary>
      /// When overridden in a derived class, performs the installation.
      /// </summary>
      /// <param name="stateSaver">An <see cref="T:System.Collections.IDictionary"/> used to save information needed to perform a commit, rollback, or uninstall operation.</param>
      /// <exception cref="T:System.ArgumentException">
      /// The <paramref name="stateSaver"/> parameter is null.
      /// </exception>
      /// <exception cref="T:System.Exception">
      /// An exception occurred in the <see cref="E:System.Configuration.Install.Installer.BeforeInstall"/> event handler of one of the installers in the collection.
      /// -or-
      /// An exception occurred in the <see cref="E:System.Configuration.Install.Installer.AfterInstall"/> event handler of one of the installers in the collection.
      /// </exception>
      public override void Install (System.Collections.IDictionary stateSaver)
      {
         base.Install(stateSaver);

         //System.Diagnostics.Debugger.Launch();
         string targetExe = Context.Parameters["assemblyPath"];
         string folderName = Path.GetDirectoryName(targetExe);

         string logFolder = Path.Combine(folderName, LOG_FOLDER);
         string pluginFolder = Path.Combine(folderName, PLUGIN_FOLDER);

         createIconedFolder(logFolder, LOG_FOLDER_ICON , 0, Properties.Resources.ttLogFolder, false, true);
         createIconedFolder(pluginFolder, PLUGIN_ICON, 0, Properties.Resources.ttPluginFolder, false, true);

      }

      /// <summary>
      /// When overridden in a derived class, completes the install transaction.
      /// </summary>
      /// <param name="savedState">An <see cref="T:System.Collections.IDictionary"/> that contains the state of the computer after all the installers in the collection have run.</param>
      /// <exception cref="T:System.ArgumentException">
      /// The <paramref name="savedState"/> parameter is null.
      /// -or-
      /// The saved-state <see cref="T:System.Collections.IDictionary"/> might have been corrupted.
      /// </exception>
      /// <exception cref="T:System.Configuration.Install.InstallException">
      /// An exception occurred during the <see cref="M:System.Configuration.Install.Installer.Commit(System.Collections.IDictionary)"/> phase of the installation. This exception is ignored and the installation continues. However, the application might not function correctly after the installation is complete.
      /// </exception>
      public override void Commit (System.Collections.IDictionary savedState)
      {
         base.Commit(savedState);

      }

      /// <summary>
      /// When overridden in a derived class, restores the pre-installation state of the computer.
      /// </summary>
      /// <param name="savedState">An <see cref="T:System.Collections.IDictionary"/> that contains the pre-installation state of the computer.</param>
      /// <exception cref="T:System.ArgumentException">
      /// The <paramref name="savedState"/> parameter is null.
      /// -or-
      /// The saved-state <see cref="T:System.Collections.IDictionary"/> might have been corrupted.
      /// </exception>
      /// <exception cref="T:System.Configuration.Install.InstallException">
      /// An exception occurred during the <see cref="M:System.Configuration.Install.Installer.Rollback(System.Collections.IDictionary)"/> phase of the installation. This exception is ignored and the rollback continues. However, the computer might not be fully reverted to its initial state after the rollback completes.
      /// </exception>
      public override void Rollback (System.Collections.IDictionary savedState)
      {
         base.Rollback(savedState);

         string targetExe = Context.Parameters["assemblyPath"];
         string folderName = Path.GetDirectoryName(targetExe);

         string logFolder = Path.Combine(folderName, LOG_FOLDER);
         string pluginFolder = Path.Combine(folderName, PLUGIN_FOLDER);

         UndoIconedFolder(logFolder);
         UndoIconedFolder(pluginFolder);
      }

      /// <summary>
      /// When overridden in a derived class, removes an installation.
      /// </summary>
      /// <param name="savedState">An <see cref="T:System.Collections.IDictionary"/> that contains the state of the computer after the installation was complete.</param>
      /// <exception cref="T:System.ArgumentException">
      /// The saved-state <see cref="T:System.Collections.IDictionary"/> might have been corrupted.
      /// </exception>
      /// <exception cref="T:System.Configuration.Install.InstallException">
      /// An exception occurred while uninstalling. This exception is ignored and the uninstall continues. However, the application might not be fully uninstalled after the uninstallation completes.
      /// </exception>
      public override void Uninstall (System.Collections.IDictionary savedState)
      {
         base.Uninstall(savedState);

         string targetExe = Context.Parameters["assemblyPath"];
         string folderName = Path.GetDirectoryName(targetExe);

         string logFolder = Path.Combine(folderName, LOG_FOLDER);
         string pluginFolder = Path.Combine(folderName, PLUGIN_FOLDER);

         UndoIconedFolder(logFolder);
         UndoIconedFolder(pluginFolder);
      }

      #endregion Installer Implementation

      #region Private Methods

      #region createIconedFolder
      /// <summary>
      /// Turns a folder into a "Special" folder, at least one that contains an icon and custom tool tip
      /// </summary>
      /// <remarks>
      /// The default for iconIndex is 0.<br></br>
      /// The default for toolTip is "".<br></br>
      /// The default for preventSharing is false.<br></br>
      /// The default for confirmDelete is true.<br></br>
      /// </remarks>
      /// <param name="folderName">The fully qualified path to the file.</param>
      /// <param name="iconFile">The Icon File to use.</param>
      /// <returns>True upon success, otherwise false.</returns>
      private bool createIconedFolder (string folderName, string iconFile)
      {
         return createIconedFolder(folderName, iconFile, 0, "", false, true);
      }

      /// <summary>
      /// Turns a folder into a "Special" folder, at least one that contains an icon and custom tool tip
      /// </summary>
      /// <param name="folderName">The fully qualified path to the file.</param>
      /// <param name="iconFile">The Icon File to use.</param>
      /// <param name="iconIndex">The index of the icon to use.</param>
      /// <param name="toolTip">The tool tip or "InfoTip" to use.</param>
      /// <param name="preventSharing">True indicates the folder can not be shared. False indicates sharing is allowed.</param>
      /// <param name="confirmDelete">True indicates the use will receive a message "You are deleting a system" when attempting
      /// to delete the folder.  False indicates that the operating system will not raise this warning.</param>
      /// <returns>True upon success, otherwise false.</returns>
      private bool createIconedFolder (string folderName, string iconFile, int iconIndex, string toolTip,
            bool preventSharing, bool confirmDelete)
      {
         #region Private Variables
         DirectoryInfo folder;
         string fileName = "desktop.ini";
         #endregion Private Variables

         #region Data Validation

         if (Directory.Exists(folderName) == false)
         {
            return false;
         }

         #endregion Data Validation

         try
         {
            folder = new DirectoryInfo(folderName);
            fileName = Path.Combine(folderName, fileName);

            // Create the file
            using (StreamWriter sw = new StreamWriter(fileName))
            {
               sw.WriteLine("[.ShellClassInfo]");
               sw.WriteLine("ConfirmFileOp={0}", confirmDelete);
               sw.WriteLine("NoSharing={0}", preventSharing);
               sw.WriteLine("IconFile={0}", iconFile);
               sw.WriteLine("IconIndex={0}", iconIndex);
               sw.WriteLine("InfoTip={0}", toolTip);
               sw.Close();
            }

            // Update the folder attributes
            folder.Attributes = folder.Attributes | FileAttributes.System;

            // "Hide" the desktop.ini
            File.SetAttributes(fileName, File.GetAttributes(fileName) | FileAttributes.Hidden);
         }
         catch
         {
            return false;
         }

         return true;
      }
      #endregion createIconedFolder

      #region UndoIconedFolder

      /// <summary>
      /// Turns a "Special" folder back into a normal folder.
      /// </summary>
      /// <param name="folderName">The folder to revert back.</param>
      /// <returns>True upon success otherwise false.</returns>
      private bool UndoIconedFolder (string folderName)
      {
         #region Private Variables
         DirectoryInfo folder;
         #endregion Private Variables

         #region Data Validation
         if (Directory.Exists(folderName) == false)
         {
            return false;
         }
         #endregion Data Validation

         try
         {
            folder = new DirectoryInfo(folderName);

            // Remove the file [Desktop.ini]
            FileInfo file = new FileInfo(Path.Combine(folderName, "desktop.ini"));
            if (file.Exists)
            {
               file.Delete();
            }

            folder.Attributes = (folder.Attributes | FileAttributes.System);
         }
         catch
         {
            return false;
         }

         return true;
      }

      #endregion UndoIconedFolder

      #endregion Private Methods
   }
}